/**
 * 
 */
package cs342.project1.mathNotebook.tests.db;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

import cs342.project1.mathNotebook.db.*;

/**
 * @author aaron
 *
 */
public class DatabaseTest {
	static DatabaseContext context = null;
	static DatabaseContext context2 = null;

	/**
	 * @throws java.lang.Exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		context = new DatabaseContext("resources/DatabaseContext-Test.properties");
		context2 = new DatabaseContext("resources/DatabaseContext-Test2.properties");

	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		DBNotebook.clearContext(context);
		DBPerson.clearContext(context);
		context.close();
		
		DBNotebook.clearContext(context2);
		DBPerson.clearContext(context2);
		context2.close();
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		DBNotebook.clearContext(context);
		DBPerson.clearContext(context);
	}
	
	@Test
	public void prefixTest() {
		assertEquals(context.getPrefixedTableName("test"), "junit_test");
	}
	
	@Test
	public void connectionTest() throws DatabaseUnconnectableException {
		assertTrue(context != null);
		context.getConnection();
		assertTrue(context.isConnected());
	}
	
	@Test
	public void tablesTest() throws DatabaseException {
		DBPerson.setUpContext(context);
		DBNotebook.setUpContext(context);
		DBNotebook.clearContext(context);
		DBPerson.clearContext(context);
	}
	
	@Test
	public void createPersonTest() throws DatabaseException {
		DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'}).invalidate();
		DBPerson p = DBPerson.getPersonByUsername(context, "testUser");
		assertEquals(p.getUsername(), "testUser");
		assertEquals(p.getFullname(), "Test User");
		assertEquals(p.getEmail(), "user@test.com");
		assertEquals(p.getPublicKey()[1], 'b');
	}
	
	@Test
	public void checkUsernameTest() throws DatabaseException {
		assertTrue(DBPerson.isUsernameAvailable(context, "testUser"));
		DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'}).invalidate();
		assertFalse(DBPerson.isUsernameAvailable(context, "testUser"));
	}
	
	@Test
	public void getAllPersonsEmptyTest() throws DatabaseException {
		assertEquals(DBPerson.getAllPersons(context).length, 0);
	}
	
	@Test
	public void getAllPersonsCreatePersonTest() throws DatabaseException {
		DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'}).invalidate();
		DBPerson.createPerson(context, "testUser2", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		context.executeSQLNoResults("INSERT INTO junit_people VALUES('testUser3','Test User', 'user@test.com', 'abc')");
		DBPerson[] people = DBPerson.getAllPersons(context);
		assertEquals(people.length, 3);
	}
	
	@Test
	public void getPersonTest() throws DatabaseException {
		DBPerson.setUpContext(context);
		context.executeSQLNoResults("INSERT INTO junit_people VALUES('testUser','Test User', 'user@test.com', 'abc')");
		DBPerson p = DBPerson.getPersonByUsername(context, "testUser");
		assertEquals(p.getUsername(), "testUser");
		assertEquals(p.getFullname(), "Test User");
		assertEquals(p.getEmail(), "user@test.com");
		assertEquals(p.getPublicKey()[1], 'b');
	}
	
	@Test
	public void createNotebookTest() throws DatabaseException {
		DBPerson p = DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		DBNotebook n = DBNotebook.createNotebook(context, p, new Date(), new byte[] {'a', 'b', 'c'});
		n.invalidate();
		assertEquals(n.getReaders().length, 0);
		assertEquals(n.getWriters().length, 0);
		assertNull("there should be no key, not a reader", n.getKeyForReader(p));
		byte[] b = new byte[] {'a', 'b', 'c'};
		n.addReader(p, b);
		byte[] newB = n.getKeyForReader(p);
		assertTrue("there should get the same key back", Arrays.equals(b, newB));
		//is owner
		assertTrue(n.hasWriter(p));
		DBPerson p2 = DBPerson.createPerson(context, "testUser2", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		assertFalse(n.hasWriter(p2));
		n.addWriter(p2);
		assertTrue(n.hasWriter(p2));
		assertEquals(n.getReaders().length, 1);
		assertEquals(n.getWriters().length, 1);
		assertEquals(n.getOwner().getUsername(), "testUser");
		assertTrue(n.getId() != -1);
	}
	
	@Test
	public void updateNotebookTest() throws DatabaseException {
		DBPerson p = DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		byte[] b = new byte[] {'a','b','c'};
		DBNotebook n = DBNotebook.createNotebook(context, p, new Date(), b);
		b = new byte[] {'1','2','3'};
		n.invalidate();
		n.setData(b);
		n.invalidate();
		byte[] newB = n.getData();
		assertTrue("should equal new data", Arrays.equals(b, newB));
	}
	
	@Test
	public void lockNotebookTest() throws DatabaseException {
		DBPerson p = DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		DBNotebook n = DBNotebook.createNotebook(context, p, new Date(), new byte[] {'a', 'b', 'c'});
		n.invalidate();
		n.addReader(p, new byte[] {'a', 'b', 'c'});
		n.addWriter(p);
		n.setLock(p, new Date());
		n.invalidate();
		assertTrue(n.isLocked());
		n.unlock();
		n.invalidate();
		assertFalse(n.isLocked());
	}
	
	@Test
	public void contextTest() throws FileNotFoundException, IOException, DatabaseException {
		DBPerson p = DBPerson.createPerson(context, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		assertEquals(DBPerson.getAllPersons(context2).length, 0);
		assertEquals(DBPerson.getAllPersons(context).length, 1);
		DBPerson p2 = DBPerson.createPerson(context2, "testUser", "Test User", "user@test.com", new byte[] { 'a', 'b' , 'c'});
		assertEquals(DBPerson.getAllPersons(context2).length, 1);
		assertEquals(DBPerson.getAllPersons(context).length, 1);
	}
	
	

}
